// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package strconv

const fnParseComplex = "ParseComplex"

// convErr将parseFloatPrefix返回的错误分解为ParseComplex的语法或范围错误。
func convErr(err error, s string) (syntax, range_ error) {
	if x, ok := err.(*NumError); ok {
		x.Func = fnParseComplex
		x.Num = s
		if x.Err == ErrRange {
			return nil, x
		}
	}
	return err, nil
}

// ParseComplex将字符串s转换为复数
// 精度由bitSize指定：64表示complex64，128表示complex128。
// 当bitSize=64时，结果的类型仍然是complex128，但它将是
// 可转换为complex64，而不更改其值。
// 
// 由s表示的数字必须是N、Ni或N±Ni的形式，其中N代表由ParseFloat识别的浮点数，i是假想的
// 分量。如果第二个N是无符号的，则两个组件
// 之间需要一个+号，如±所示。如果第二个N为NaN，则只接受+号。
// 表单可以用括号括起来，不能包含任何空格。
// 得到的复数由ParseFloat转换的两个分量组成。
// 
// 解析复杂返回的错误具有具体类型*numerior 
// 并包含错误。Num=s.
// 
// 如果s的语法格式不正确，ParseComplex将返回err。Err=Err语法。
// 
// 如果s在语法上格式良好，但其中任何一个组件与给定组件大小的最大浮点数相差超过1/2 ULP 
// 
// ParseComplex返回err。Err=各部件的ErrRange和c=±Inf。
func ParseComplex(s string, bitSize int) (complex128, error) {
	size := 64
	if bitSize == 64 {
		size = 32 // complex64使用float32部分
	}

	orig := s

	// 删除括号（如果有）。
	if len(s) >= 2 && s[0] == '(' && s[len(s)-1] == ')' {
		s = s[1 : len(s)-1]
	}

	var pending error // 挂起的范围错误，或nil 

	// 读取实部（如果后跟“i”，则可能是虚部）。
	re, n, err := parseFloatPrefix(s, size)
	if err != nil {
		err, pending = convErr(err, orig)
		if err != nil {
			return 0, err
		}
	}
	s = s[n:]

	// 如果我们什么都没有了，我们就完了。
	if len(s) == 0 {
		return complex(re, 0), pending
	}

	// 否则，请看下一个字符。
	switch s[0] {
	case '+':
		// 如果我们有“+NaNi”，则使用“+”以避免错误，但
		// 只有在我们没有“+”（不要隐藏该错误）时才这样做。
		if len(s) > 1 && s[1] != '+' {
			s = s[1:]
		}
	case '-':
		// 好的
	case 'i':
		// 如果“i”是最后一个字符，我们只有一个虚部。读虚部。
		if len(s) == 1 {
			return complex(0, re), pending
		}
		fallthrough
	default:
		return 0, syntaxError(fnParseComplex, orig)
	}

	im, n, err := parseFloatPrefix(s, size)
	if err != nil {
		err, pending = convErr(err, orig)
		if err != nil {
			return 0, err
		}
	}
	s = s[n:]
	if s != "i" {
		return 0, syntaxError(fnParseComplex, orig)
	}
	return complex(re, im), pending
}
